package com.mutouren.modules.datapush.base;

import java.io.ByteArrayOutputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;

import com.mutouren.common.exception.ExceptionUtils;
import com.mutouren.common.utils.UUIDUtils;

public class PushMessage implements Gradable {	
	private long id;
	private String guid;
	private String url;
	private String methodAlias;
	private String requestBody;
	private String response;
	
	private MethodType methodType;
	private ContentType contentType; 
	private Charset charset;
		
	private PushStatus pushStatus;
	private Date createTime;
	private Date lastUpdateTime;
	
	private int requestCount;
	private int version;
	private boolean isFinish;
	
	public void thinData() {
		this.url = null;
		this.requestBody = null;
		this.response = null;
	}
	
	public PushMessage() {
		this.createTime = new Date();
		this.lastUpdateTime = new Date();
		this.pushStatus = PushStatus.INIT;	
		this.setRequestCount(0);
		//this.guid = UUID.randomUUID().toString();
		this.guid = UUIDUtils.createBase64UUID();
		this.isFinish = false;
	}
	
	public PushMessage(String url, String methodAlias, String requestBody, MethodType methodType,
		ContentType contentType, Charset charset) {	
		
		this.url = url == null ? "" : url;
		this.methodAlias = methodAlias;
		this.requestBody = requestBody;
		this.methodType = methodType;
		this.contentType = contentType;

		this.charset = charset;
		
		this.createTime = new Date();
		this.lastUpdateTime = new Date();
		this.pushStatus = PushStatus.INIT;		
		this.setRequestCount(0);
		//this.guid = UUID.randomUUID().toString();
		this.guid = UUIDUtils.createBase64UUID();
		this.isFinish = false;
	}	
		
	public String getGuid() {
		return guid;
	}
	public void setGuid(String guid) {
		this.guid = guid;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getMethodAlias() {
		return methodAlias;
	}
	public void setMethodAlias(String methodAlias) {
		this.methodAlias = methodAlias;
	}
	public String getRequestBody() {
		return requestBody;
	}
	public void setRequestBody(String requestBody) {
		this.requestBody = requestBody;
	}
	public String getResponse() {
		return response;
	}
	public void setResponse(String response) {
		this.response = response;
	}
	public MethodType getMethodType() {
		return methodType;
	}
	public void setMethodType(MethodType methodType) {
		this.methodType = methodType;
	}
	public PushStatus getPushStatus() {
		return pushStatus;
	}
	public void setPushStatus(PushStatus pushStatus) {
		this.pushStatus = pushStatus;
	}
	public Date getCreateTime() {
		return createTime;
	}
	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}
	public Date getLastUpdateTime() {
		return lastUpdateTime;
	}
	public void setLastUpdateTime(Date lastUpdateTime) {
		this.lastUpdateTime = lastUpdateTime;
	}

	public ContentType getContentType() {
		return contentType;
	}
	public void setContentType(ContentType contentType) {
		this.contentType = contentType;
	}
	public Charset getCharset() {
		return charset;
	}
	public void setCharset(Charset charset) {
		this.charset = charset;
	}

	public int getRequestCount() {
		return requestCount;
	}

	public void setRequestCount(int requestCount) {
		this.requestCount = requestCount;
	}
	
	@Override
	public int getGrade() {
		return this.requestCount;
	}
	
	public String getRealUrl() {
		if ((methodType == MethodType.GET)&&(!StringUtils.isBlank(this.getRequestBody()))) {
			if(this.getUrl().indexOf("?") > 0) {
				return String.format("%s&%s", this.url, this.getRequestBody());
			} else {
				return String.format("%s?%s", this.url, this.getRequestBody());
			}
		} else {
			return this.getUrl();
		}
	}
	
	/**
	 * 
	 * format:utf-8
	 * guid,methodAlias,methodType,contentType,charset,pushStatus,requestCount,
	 * createTime(yyyy-MM-dd HH:mm:ss),lastTime(yyyy-MM-dd HH:mm:ss),url_length,body_length\n
	 * url\nbody\n
	 * 
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public byte[] encode() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		
		try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
			byte[] urlBytes = this.url.getBytes(Charset.UTF_8.name);
			byte[] bodyBytes = this.requestBody.getBytes(Charset.UTF_8.name);
			byte[] headBytes = String.format("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", 
					this.guid,this.methodAlias,this.methodType.value,this.contentType.value,
					this.charset.value,this.pushStatus.value,this.requestCount,
					sdf.format(this.createTime),sdf.format(this.lastUpdateTime),
					urlBytes.length,bodyBytes.length
					).getBytes(Charset.UTF_8.name);
			
			out.write(headBytes);
			out.write(urlBytes);
			out.write('\n');
			out.write(bodyBytes);
			out.write('\n');
			return out.toByteArray();
		} catch(Throwable t) {
			throw ExceptionUtils.doUnChecked(t);
		}
	}
	
	public static PushMessage decode(byte[] arrData) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		
		try {
			PushMessage result = new PushMessage();
			int index = 0;
			for(int i = 0; i < arrData.length; i++) {
				if (arrData[i] == '\n'){
					index = i;break;
				}
			}
			
			if (index == 0) {
				throw new RuntimeException("PushMessage.decode error, not find flag index");
			}			
			String[] arrHead = new String(Arrays.copyOf(arrData, index), Charset.UTF_8.name).split(",");
			int urlLen = Integer.parseInt(arrHead[9]);
			int bodyLen = Integer.parseInt(arrHead[10]);
			
			String url = new String(Arrays.copyOfRange(arrData, index+1, index+1+urlLen), Charset.UTF_8.name);
			String body = new String(Arrays.copyOfRange(arrData, index+2+urlLen, index+2+urlLen+bodyLen), Charset.UTF_8.name);
			
			result.setGuid(arrHead[0]);
			result.setMethodAlias(arrHead[1]);
			result.setMethodType(MethodType.valueOf(Byte.valueOf(arrHead[2])));
			result.setContentType(ContentType.valueOf(Byte.valueOf(arrHead[3])));
			result.setCharset(Charset.valueOf(Byte.valueOf(arrHead[4])));
			
			result.setPushStatus(PushStatus.valueOf(Byte.valueOf(arrHead[5])));
			result.setRequestCount(Integer.valueOf(arrHead[6]));
			result.setCreateTime(sdf.parse(arrHead[7]));
			result.setLastUpdateTime(sdf.parse(arrHead[8]));
			
			result.setUrl(url);
			result.setRequestBody(body);
			
			return result;
			
		} catch(Throwable t) {
			throw ExceptionUtils.doUnChecked(t);
		}
	}

	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public int getVersion() {
		return version;
	}
	public void setVersion(int version) {
		this.version = version;
	}

	public boolean getIsFinish() {
		return isFinish;
	}

	public void setIsFinish(boolean isFinish) {
		this.isFinish = isFinish;
	}	
}
